#pragma once

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/select.h>
#include <unistd.h>
#include <fcntl.h>
#include <iostream>
#include <list>
#include <vector>

class server
{
private:
    void error_handler(const char *str)
    {
        std::cout << str << std::endl;
        exit(-1);
    }

    void setnoblocking(int fd)
    {
        int flags = fcntl(fd,F_GETFL,0);
        fcntl(fd,F_SETFL,flags | O_NONBLOCK);
    }
public:
    server(int port)
    {
        _listenfd = socket(AF_INET,SOCK_STREAM,0);
        if(_listenfd == -1) error_handler("socket error!");

        int val = 1;
        int n = setsockopt(_listenfd,SOL_SOCKET,SO_REUSEADDR,&val,sizeof(val));
        if(n == -1) error_handler("setsockopt error!");

        sockaddr_in server;
        memset(&server,0,sizeof(server));
        server.sin_family = AF_INET;
        server.sin_port = htons(port);
        server.sin_addr.s_addr = INADDR_ANY;
        n = bind(_listenfd,(sockaddr *)&server,sizeof(server));
        if(n == -1) error_handler("bind error!");

        n = listen(_listenfd,5);
        _connfds.push_back(_listenfd);
    }

    ~server()
    {
        close(_listenfd);
    }

    void start()
    {
        while(true)
        {
            _maxfd = 0;
            FD_ZERO(&_read);
            for(auto &e:_connfds)
            {
                FD_SET(e,&_read);
                FD_SET(e,&_write);
                if(_maxfd < e) _maxfd = e;
            }
            timeval timeout = {0,0};// 非阻塞
            int ret = select(_maxfd+1,&_read,&_write,nullptr,&timeout);
            if(ret == 0) continue;
            if(ret == -1)
            {
                std::cerr << "select error: " << strerror(errno) << std::endl;
                break;
            }
            else 
            {
                if(FD_ISSET(_listenfd,&_read))
                {
                    sockaddr_in client;
                    socklen_t len = sizeof(client);
                    int connfd = accept(_listenfd,(sockaddr *)&client,&len);
                    std::cout << "new connection: "<< connfd << " ip: " << inet_ntoa(client.sin_addr) << std::endl;
                    _connfds.push_back(connfd);
                }
                else 
                {
                    std::vector<int> del;
                    for(auto &e:_connfds)
                    {
                        if(FD_ISSET(e,&_read))
                        {
                            char buffer[1024] = {0};
                            int recv_len = recv(e,buffer,sizeof(buffer)-1,0);
                            if(recv_len > 0)
                            {
                                buffer[recv_len] = 0;
                                std::cout << "服务器接收到消息: " << buffer << std::endl;
                            }
                            else if(recv_len == 0)
                            {
                                close(e);
                                del.push_back(e);
                                std::cout << e << "号客户端断开连接!" << std::endl;
                            }
                        }
                        // else if(FD_ISSET(e,&_write))
                        // {
                        //     char buffer[] = 
                        //         "HTTP/1.1 200 OK\r\n"
                        //         "Content-Type: text/html\r\n"
                        //         "Connection: keep-alive\r\n"
                        //         "Keep-Alive: timeout=5, max=100\r\n"
                        //         "\r\n"
                        //         "<html><body><img src=\"boat.gif\" alt=\"Big Boat\"><h1>Hello, World!</h1></body></html>";
                        //     int n = send(e,buffer,sizeof(buffer),0);
                        //     if(n == 0)
                        //     {
                        //         close(e);
                        //         del.push_back(e);
                        //         std::cout << e << "号客户端断开连接!" << std::endl;
                        //     }
                        // }
                    }
                    for(auto &e:del) _connfds.remove(e);
                }
            }
        }
    }
protected:
    int _listenfd;
    fd_set _read;
    fd_set _write;
    std::list<int> _connfds;
    int _maxfd;
};